#include "ws_server.h"
#include "ws_server_c.h"
#include "elog.h"
#include "elog_file.h"
#include "ws_constant.h"
#include "dwarf_utils.h"
#include "test_data.h"
#include "notify.h"
#include "notify.pb.h"
#include "ws_version.h"

#include "libhv/hv.h"

#include <iostream>
#include <fstream>
#include <unordered_map>
#include <map>

#define MAX_WS_CHANNEL  5
#define MAX_CLIENT      3
#define PROTOBUF_MAJOR_VERSION 1
#define PROTOBUF_MINOR_VERSION 2

static std::string pong = "pong";
static std::unordered_map<int, WebSocketChannelPtr> channels;
static std::mutex ws_mutex;
static std::map<std::string, int> map_client_ids;

static Notify* m_notify = Notify::getInstance();
static std::string master_client_id;
static long ws_client_timestamp;
static long master_client_disconnect_timestamp = 0;
static bool b_lock_master = false;

//函数指针表
static std::unordered_map<int, int (WsServer::*)(WsPacket& ws_packet)> func_table {
    { MODULE_CAMERA_TELE, &WsServer::handleCameraMessage },
    { MODULE_ASTRO, &WsServer::handleAstroMessage },
    { MODULE_CAMERA_WIDE, &WsServer::handleCamWideMessage },
    { MODULE_SYSTEM, &WsServer::handleSystemMessage },
    { MODULE_RGB_POWER, &WsServer::handleRgbPowerMessage },
    { MODULE_MOTOR, &WsServer::handleMotorMessage },
    { MODULE_TRACK, &WsServer::handleTrackMessage },
    { MODULE_FOCUS, &WsServer::handleFocusMessage },
    { MODULE_PANORAMA, &WsServer::handlePanormaMessage },
    { MODULE_NOTIFY, &WsServer::handleNotifyMessage },
    { MODULE_ITIPS, &WsServer::handleITipsMessage }
};

WsServer::WsServer() {
    p_thread_pool_ =  ThreadPool::GetInstance(50);
    cam_tele_ = CamTele();
    p_state_manager = StateManager::GetInstance();
    cam_wide_ = CamWide();
    system_ = System();
    rgb_power_ = RgbPower();
    motor_controller_ = MotorController();
    focus_ = Focus();

    StepMotorUser& motor_yaw = MotorController::motorYaw();
    StepMotorUser& motor_pitch = MotorController::motorPitch();
    panorama_ = Dwarf2Panorama(&motor_yaw,&motor_pitch,&cam_tele_);
}

WsServer::~WsServer() {

}

/*
指定ws客户端id
*/
int setWsPacketByClientId(WsPacket& ws_packet, int cmd, int module_id, int type, const std::string& client_id) {
    ws_packet.set_major_version(PROTOBUF_MAJOR_VERSION);
    ws_packet.set_minor_version(PROTOBUF_MINOR_VERSION);
    ws_packet.set_device_id(WS_DEVICE_ID);
    ws_packet.set_cmd(cmd);
    ws_packet.set_module_id(module_id);
    ws_packet.set_type(type);
    ws_packet.set_client_id(client_id);

    return 0;
}

int setWsPacket(WsPacket& ws_packet, int cmd, int module_id, int type) {
    ws_packet.set_major_version(PROTOBUF_MAJOR_VERSION);
    ws_packet.set_minor_version(PROTOBUF_MINOR_VERSION);
    ws_packet.set_device_id(WS_DEVICE_ID);
    ws_packet.set_cmd(cmd);
    ws_packet.set_module_id(module_id);
    ws_packet.set_type(type);

    return 0;
}

/*
指定ws客户端id
*/
int wsResponseByClientId(std::string &serialized_data, int cmd, int module_id, int type, const std::string& client_id) {
    WsPacket ws_packet;
    setWsPacketByClientId(ws_packet, cmd, module_id, type, client_id);
    ws_packet.set_data(serialized_data);

    std::string packet_serialized_data;
    ws_packet.SerializeToString(&packet_serialized_data);
   
    std::lock_guard<std::mutex> lock(ws_mutex);

    auto it = map_client_ids.find(client_id);
    if (it != map_client_ids.end()) {
        auto it_ = channels.find(it->second);
        if (it_ != channels.end()) {
            it_->second->send(packet_serialized_data, WS_OPCODE_BINARY);
        }
    }

    return 0;
}

int wsResponsePacket(const WsPacket& ws_packet) {
    std::string packet_serialized_data;
    ws_packet.SerializeToString(&packet_serialized_data);

   
    std::lock_guard<std::mutex> lock(ws_mutex);

    auto it = map_client_ids.find(ws_packet.client_id());
    if (it != map_client_ids.end()) {
        auto it_ = channels.find(it->second);
        if (it_ != channels.end()) {
            log_i("send ws_packet module_id = %d, cmd = %d, type = %d, client_id = %s", ws_packet.module_id(), ws_packet.cmd(), ws_packet.type(), ws_packet.client_id().c_str());
            it_->second->send(packet_serialized_data, WS_OPCODE_BINARY);
        }
    }

    return 0;
}

/*
广播
*/
int wsResponse(std::string &serialized_data, int cmd, int module_id, int type) {
    for (auto& pair : map_client_ids) {
        WsPacket ws_packet;
        setWsPacketByClientId(ws_packet, cmd, module_id, type, pair.first);
        ws_packet.set_data(serialized_data);
        std::string packet_serialized_data;
        ws_packet.SerializeToString(&packet_serialized_data);

        std::lock_guard<std::mutex> lock(ws_mutex);
        auto it = channels.find(pair.second);
        if (it != channels.end()) {
            it->second->send(packet_serialized_data, WS_OPCODE_BINARY);
        }

        // log_i("SEND CMD ID:%d", cmd);
    }

    return 0;
}

/*
状态通知的广播
*/
int wsResponseNotify(std::string &serialized_data, int cmd, int module_id, int type) {
    for (auto& pair : map_client_ids) {
        WsPacket ws_packet;
        setWsPacketByClientId(ws_packet, cmd, module_id, type, pair.first);
        ws_packet.set_data(serialized_data);
        std::string packet_serialized_data;
        ws_packet.SerializeToString(&packet_serialized_data);

        m_notify->addWsMessage(ws_packet);

        std::lock_guard<std::mutex> lock(ws_mutex);
        auto it = channels.find(pair.second);
        if (it != channels.end()) {
            it->second->send(packet_serialized_data, WS_OPCODE_BINARY);
        }
    }

    return 0;
}

int WsServer::handleCameraMessage(WsPacket& ws_packet) {
    cam_tele_.handleMessage(ws_packet);

    return 0;
}

int WsServer::handleCamWideMessage(WsPacket& ws_packet) {
    cam_wide_.handleMessage(ws_packet);

    return 0;
}

int WsServer::handleAstroMessage(WsPacket& ws_packet) {
    astro_.handleMessage(ws_packet);
    
    return 0;
}

int WsServer::handleSystemMessage(WsPacket& ws_packet) {
    system_.handleMessage(ws_packet);

    return 0;
}

int WsServer::handleRgbPowerMessage(WsPacket& ws_packet) {
    rgb_power_.handleMessage(ws_packet);
    return 0;
}

int WsServer::handleMotorMessage(WsPacket& ws_packet) {
    motor_controller_.handleMessage(ws_packet);

    return 0;
}

int WsServer::handleTrackMessage(WsPacket& ws_packet) {
    track_.handleMessage(ws_packet);
    return 0;
}

int WsServer::handleFocusMessage(WsPacket& ws_packet) {
    focus_.handleMessage(ws_packet);

    return 0;
}

int WsServer::handlePanormaMessage(WsPacket& ws_packet){
    panorama_.handleMessage(ws_packet);
    return 0;
}

int WsServer::handleNotifyMessage(WsPacket& ws_packet) {
    m_notify->handleMessage(ws_packet);

    return 0;
}

int WsServer::handleITipsMessage(WsPacket& ws_packet) {
    itips_.handleMessage(ws_packet);

    return 0;
}

int WsServer::dispatchMessage(WsServer* ws_server,const std::string& msg, int channel_id) {
    // log_i("handle message");

    WsPacket ws_packet;
    if (!ws_packet.ParseFromString(msg)) {
        return -WS_PARSE_PROTOBUF_ERROR;
    }
    
    int module_id = ws_packet.module_id();
    int cmd = ws_packet.cmd();
    int major_version = ws_packet.major_version();
    int minor_version = ws_packet.minor_version();
    std::string client_id = ws_packet.client_id();
    // log_i("client id = %s", client_id.c_str());
    if (map_client_ids.size() < MAX_CLIENT) {
        ws_server->addClientId(channel_id, client_id, major_version, minor_version);
    } else {
        log_e("map_cilent_id size = %d, reach max_client count", map_client_ids.size());
    }
    
    if (client_id != master_client_id) {
        log_e("client is not master, can not operator");
        // 从设备只能获取参数和状态
        if (cmd != CMD_CAMERA_TELE_GET_ALL_PARAMS && cmd != CMD_CAMERA_TELE_GET_ALL_FEATURE_PARAMS && cmd != CMD_CAMERA_WIDE_GET_ALL_PARAMS && cmd != CMD_CAMERA_TELE_GET_SYSTEM_WORKING_STATE)
            return 0;
    }

    //在表中查找函数指针并调用
    auto it = func_table.find(module_id);
    if (it != func_table.end()) {
        (ws_server->*(it->second))(ws_packet);
    }
    else {
        log_i("Function not found");
    }

    return 0;
}



int WsServer::startWsServer() {
    testDataAll();
    log_i("start libhv websocket server");

    ws_client_timestamp = getTimestampInSeconds();
    log_i("ws client timelapse = %lld", ws_client_timestamp);

    this->server.port = 9900;
    this->server.ws = &ws;

    ws.onopen = [this](const WebSocketChannelPtr& channel, const HttpRequestPtr& req) {
        log_i("onopen: GET %s\n", req->Path().c_str());
        addChannel(channel);
    };

    ws.onmessage = [this](const WebSocketChannelPtr& channel, const std::string& msg) {
        // log_i("channel opcode = %d, msg = %s", channel->opcode, msg.c_str());
        if (channel->opcode == 1 && msg == "ping") {
            log_i("receive ping msg: %s, channel id = %d", msg.c_str(), channel->id());
            channel->send(pong);
            ws_client_timestamp = getTimestampInSeconds();
        } else {
            p_thread_pool_->enqueue(this->dispatchMessage, this, msg, channel->id());
        }
    };

    ws.onclose = [this](const WebSocketChannelPtr& channel) {
        log_i("onclose channel id = %d", channel->id());
        removeChannel(channel);
    };

    websocket_server_run(&this->server);
    
    return 0;
}

void WsServer::addChannel(const WebSocketChannelPtr& channel) {
    log_i("add channel id = %d", channel->id());
    std::lock_guard<std::mutex> lock(ws_mutex);

    auto it = channels.find(channel->id());
    if (it == channels.end()) {
        channels[channel->id()] = channel;
        channel->setReadTimeout(30000);
    }
        
    if (channels.size() == 1) {
        rgb_power_.setRgbEffect(RGB_EFFECT_WORKING_STATE);
    }
}

void WsServer::removeChannel(const WebSocketChannelPtr& channel) {
    std::lock_guard<std::mutex> lock(ws_mutex);
    std::string client_id;

    log_i("remove channel_id = %d", channel->id());

    // 查找与断开的channel关联的client_id
    for (const auto& pair : map_client_ids) {
        if (pair.second == channel->id()) {
            client_id = pair.first;
            break;
        }
    }

    auto it = channels.find(channel->id());
    if (it != channels.end()) {
        channels.erase(it);

        // 如果断开的是主机
        if (master_client_id == client_id) {
            master_client_disconnect_timestamp = getTimestampInSeconds();
            // 启动后台线程或定时器来处理30秒后的逻辑
            std::thread([this]() {
                std::this_thread::sleep_for(std::chrono::seconds(40));
                checkAndSwitchMaster();
            }).detach();
        } else {
            // 如果是从机，直接移除
            map_client_ids.erase(client_id);
        }

        if (channels.empty()) {
            rgb_power_.setRgbEffect(RGB_EFFECT_WORKING_STATE);
        }
    }
}


void WsServer::addClientId(int channel_id, const std::string& client_id, int major_version, int minor_version) {
    std::lock_guard<std::mutex> lock(ws_mutex);
    if (client_id == master_client_id) {
        // log_i("update client id = %s, channel_id = %d", client_id.c_str(), channel_id);
        map_client_ids[client_id] = channel_id; // 添加或更新 channel_id

        return;
    }

    if (map_client_ids.find(client_id) == map_client_ids.end()) {
        log_i("add client id = %s, channel_id = %d", client_id.c_str(), channel_id);
        map_client_ids[client_id] = channel_id;
        if (map_client_ids.size() == 1 && !b_lock_master) {
            master_client_id = client_id;
            WsVersion ws_version(major_version, minor_version);
            if (ws_version.isGreaterThan(1, 1)) {
                b_lock_master = true;
                log_i("set lock master = %d", b_lock_master);
            }
                
            log_i("master client id = %s", master_client_id.c_str());
        }
    }
}

void WsServer::removeClientId(const std::string& client_id) {
    // std::lock_guard<std::mutex> lock(ws_mutex);
    auto it = map_client_ids.find(client_id);
    if (it != map_client_ids.end()) {
        log_i("remove client id = %s", client_id.c_str());
        map_client_ids.erase(it);
    }
}


void WsServer::UpdateMasterClientId() {
    if (!map_client_ids.empty() && map_client_ids.begin()->first != master_client_id && !b_lock_master) {
        log_i("change master from %s to %s", master_client_id.c_str(), map_client_ids.begin()->first .c_str());
        master_client_id = map_client_ids.begin()->first;

        ResNotifyHostSlaveMode res_notify_host_slave_mode;

        res_notify_host_slave_mode.set_mode(WS_HOST);

        std::string serialized_data;
        res_notify_host_slave_mode.SerializeToString(&serialized_data);
        WsPacket ws_packet;
        setWsPacketByClientId(ws_packet, CMD_NOTIFY_WS_HOST_SLAVE_MODE, MODULE_NOTIFY, CMD_TYPE_NOTIFICATION, master_client_id);
        ws_packet.set_data(serialized_data);

        std::string packet_serialized_data;
        ws_packet.SerializeToString(&packet_serialized_data);
    
        auto it_ = channels.find(map_client_ids.begin()->second);
        if (it_ != channels.end()) {
            it_->second->send(packet_serialized_data, WS_OPCODE_BINARY);
        }
    }
}


int getWsHostSlaveModeById(const std::string& client_id) {
    std::lock_guard<std::mutex> lock(ws_mutex);
    return client_id == master_client_id ? WS_HOST : WS_SLAVE;
}

long getWsClientTimelapse() {
    return ws_client_timestamp;
}

void updateWsClientTimlapse() {
    ws_client_timestamp = getTimestampInSeconds();
    log_i("update ws client timelapse = %lld", ws_client_timestamp);
}

int getWsConnectionState() {
    if (channels.empty())
        return -1;
    else
        return 0;
}

int setWsLockMaster(bool lock_master) {
    std::lock_guard<std::mutex> lock(ws_mutex);
    b_lock_master = lock_master;
    

    return 0;
}

bool getWsLockMaster() {
    std::lock_guard<std::mutex> lock(ws_mutex);
    
    return b_lock_master;
}

void WsServer::checkAndSwitchMaster() {
    std::lock_guard<std::mutex> lock(ws_mutex);
    log_i("check and switch master");
    // 检查是否已经超过30秒
    long cur_timestamp = getTimestampInSeconds();
    log_i("cur timestamp = %ld, master_client_disconnect_timestamp = %d", cur_timestamp, master_client_disconnect_timestamp);
    
    if (cur_timestamp - master_client_disconnect_timestamp >= 40) {
        // 检查主机是否在 map_client_ids 中
        auto it = map_client_ids.find(master_client_id);
        if (it != map_client_ids.end()) {
            // 检查对应的 channel 是否仍然存在且连接
            auto channel_it = channels.find(it->second);
            if (channel_it == channels.end() || !channel_it->second->isConnected()) {
                // 主机未重连，移除并切换主机
                removeClientId(master_client_id);
                UpdateMasterClientId();
            }
        } else {
            // 如果主机的 client_id 不在 map_client_ids 中
            removeClientId(master_client_id);
            UpdateMasterClientId();
        }
    }
}
